#include "NodeLeaf.h"
#include "../../Commons/Utils.h"
using namespace Tree;
using namespace Commons;

NodeLeaf::NodeLeaf() :
	Node() {

	this->nextLeaf = 0;
}

void NodeLeaf::addInNode(RecordNode* recordNodeToAdd) {

	RecordNode* recordToUpdate = Utils::getRecordNodeIn(recordNodeToAdd->getKey(), getRecordNodes());

	if (recordToUpdate == NULL) {
		recordToUpdate = recordNodeToAdd;
		getRecordNodes()->push_back(recordToUpdate);
	} else {

		for (unsigned int i = 0; i < recordNodeToAdd->getOffsets()->size(); i++) {
			recordToUpdate->getOffsets()->push_back(recordNodeToAdd->getOffsets()->at(i));
		}
		delete recordNodeToAdd;
	}

	//sort
	Utils::sortRecordsByKey(getRecordNodes());
}

void NodeLeaf::removeInNode(string keyToDelete) {

	for (unsigned int i = 0; i < getRecordNodes()->size(); i++) {

		if (getRecordNodes()->at(i)->getKey() == keyToDelete) {
			getRecordNodes()->erase(getRecordNodes()->begin() + i);
			break;
		}
	}
}

int NodeLeaf::getNextLeaf() {
	return nextLeaf;
}

void NodeLeaf::setNextLeaf(int nextLeafNumber) {
	this->nextLeaf = nextLeafNumber;
}

//IRecordable methods

void NodeLeaf::fillEntity(char *buffer, unsigned int bufferSize) {

	stringstream* ss = new stringstream(stringstream::in | stringstream::out | stringstream::binary);
	unsigned int nodeLevel = 0;
	unsigned int numberOfElements = 0;
	unsigned int nextLeaf = 0;

	//write buffer into stringStream
	ss->seekg(0, ios::beg);
	ss->write(buffer, bufferSize);

	//fill level
	ss->read((char*) &nodeLevel, sizeof(int));
	this->setLevel(nodeLevel);

	//fill number of RecordNodes
	ss->read((char*) &numberOfElements, sizeof(int));

	//fill next leaf reference
	ss->read((char*) &nextLeaf, sizeof(int));
	this->setNextLeaf(nextLeaf);

	//fill records
	for (unsigned int i = 0; i < numberOfElements; i++) {

		RecordNode* record = new RecordNode(); // Record: key and offsets
		string key;
		unsigned int numberOfOffsets = 0;

		key = Utils::GetNextStringValue(ss);
		record->setKey(key);
		ss->read((char*) &(numberOfOffsets), sizeof(int));

		for (unsigned int j = 0; j < numberOfOffsets; j++) {
			int offset = 0;
			ss->read((char*) &(offset), sizeof(int));

			if (offset != 0)
				record->getOffsets()->push_back(offset);
		}

		this->getRecordNodes()->push_back(record);
	}
}

char* NodeLeaf::buildBuffer() {

	stringstream* ss = new stringstream(stringstream::in | stringstream::out | stringstream::binary);
	unsigned int nodeLevel = getLevel();
	unsigned int numberOfElements = getRecordNodes()->size();
	unsigned int nextLeaf = getNextLeaf();
	unsigned int bufferSize = getBufferSize();
	char* buffer = new char[bufferSize];

	//add header
	ss->seekp(0, ios::end);
	ss->write((char*) &nodeLevel, sizeof(int));
	ss->write((char*) &numberOfElements, sizeof(int));
	ss->write((char*) &nextLeaf, sizeof(int));

	//add records
	for (unsigned int i = 0; i < numberOfElements; i++) {

		RecordNode* currentRecord = getRecordNodes()->at(i); // Record: key and offsets
		unsigned int keySize = currentRecord->getKey().size();
		unsigned int numberOfOffsets = currentRecord->getOffsets()->size();

		ss->write((char*) &keySize, sizeof(int));
		ss->write(currentRecord->getKey().c_str(), keySize);
		ss->write((char*) &numberOfOffsets, sizeof(int));

		for (unsigned int j = 0; j < numberOfOffsets; j++) {

			unsigned int offset = currentRecord->getOffsets()->at(j);
			ss->write((char*) &(offset), sizeof(int));
		}
	}

	//build buffer
	ss->read(buffer, bufferSize);

	return buffer;

}

unsigned int NodeLeaf::getBufferSize() {

	unsigned int toReturn = (sizeof(int) * 3); //header

	for (unsigned int i = 0; i < getRecordNodes()->size(); i++) {
		// Record: key and offsets
		RecordNode* currentRecord = getRecordNodes()->at(i);
		toReturn += sizeof(int) + currentRecord->getKey().size();
		toReturn += sizeof(int) + (sizeof(int) * currentRecord->getOffsets()->size()); // numberOfOffset + each offset
	}

	return toReturn;
}

NodeLeaf::~NodeLeaf() {

}
